from flask import Flask, render_template, redirect, url_for, flash, request, session, jsonify
from werkzeug.security import generate_password_hash, check_password_hash
from flask_sqlalchemy import SQLAlchemy
from models import db, User, Book, Bookshelf, ReadingProgress, Review, UserPreference
from config import Config
from sqlalchemy.sql import or_
import json
import random
from werkzeug.utils import secure_filename
import os
import time 

app = Flask(__name__)
app.secret_key = 'your_secret_key'  # 添加密钥以支持 session 和闪现消息

app.config.from_object(Config)  

# 初始化 SQLAlchemy
db.init_app(app) 

# 注册和登录表单处理函数
def validate_register_form(data):
    username = data.get('username')
    password = data.get('password')
    confirm_password = data.get('confirm_password')
    if not username or len(username) < 3 or len(username) > 20:
        return False, "用户名长度必须在3到20之间"
    if not password or len(password) < 6:
        return False, "密码长度必须至少为6"
    if password != confirm_password:
        return False, "两次输入的密码不匹配"
    return True, ""

def validate_login_form(data):
    username = data.get('username')
    password = data.get('password')
    if not username or not password:
        return False, "请输入账号和密码"
    return True, ""

def load_books_data():
    with open('books.json', 'r', encoding='utf-8') as f:
        return json.load(f)

# 定义路由
def get_recommendations(user=None, limit=20):
    """
    返回最多 limit 本书的推荐列表：
    - 若 user 为空或无标签 -> 随机
    - 若 user 看过的书有标签 -> 按标签匹配后随机挑一些
    """
    if not user:
        # 未登录：随机
        count = Book.query.count()
        if count == 0:
            return []
        all_books = Book.query.all()
        if count <= limit:
            return all_books
        return random.sample(all_books, limit)
    else:
        # 已登录：根据用户收藏或阅读过的书来推
        user_books = (db.session.query(Book)
                      .join(Bookshelf.books)  # 多对多中间表
                      .join(Bookshelf.user)
                      .filter(Bookshelf.user_id == user.id)
                      .all())
        if not user_books:
            # 用户没收藏任何书 -> 随机
            return get_recommendations(user=None, limit=limit)

        user_tags = set()
        user_book_ids = set()
        for b in user_books:
            user_book_ids.add(b.id)
            if b.tags:  # tags是个list (JSON)
                for t in b.tags:
                    user_tags.add(t)

        if not user_tags:
            # 无标签 -> 随机
            return get_recommendations(user=None, limit=limit)

        # 用like做简易匹配
        clauses = []
        for tag in user_tags:
            clauses.append(Book.tags.like(f'%{tag}%'))
        if not clauses:
            # 万一出现空
            return get_recommendations(user=None, limit=limit)

        candidates = (Book.query
                      .filter(Book.id.notin_(user_book_ids))  # 不推已经收藏/读过的
                      .filter(or_(*clauses))
                      .all())
        if not candidates:
            # 没找到符合的，再随机
            return get_recommendations(user=None, limit=limit)

        if len(candidates) <= limit:
            return candidates
        else:
            return random.sample(candidates, limit)

def get_avatar_path(logged_in):
    """根据登录状态获取用户头像路径"""
    if logged_in:
        uploads_dir = os.path.join(app.root_path, 'static', 'uploads')
        if os.path.exists(uploads_dir):
            # 获取按修改时间排序的文件列表
            files = sorted(
                os.listdir(uploads_dir),
                key=lambda x: os.path.getmtime(os.path.join(uploads_dir, x)),
                reverse=True  # 按时间降序排列
            )
            if files:
                return f'uploads/{files[0]}'  # 返回修改时间最晚的文件
        return 'profile_picture.svg'  # 若 uploads 为空或不存在，返回默认头像
    else:
        return 'profile_picture.svg'  # 未登录时返回默认头像

@app.route('/')
def index():
    books_data = Book.query.all()
    logged_in = session.get('logged_in', False)  # 获取登录状态
    avatar_path = url_for('static', filename=get_avatar_path(logged_in))
    user = {"avatar_path": avatar_path}
    return render_template('index.html', books=books_data, user=user)

@app.route('/api/recommend', methods=['GET'])
def api_recommend():
    # 根据是否登录，调用推荐逻辑
    user = None
    if session.get('logged_in'):
        user_id = session['user_id']
        user = User.query.get(user_id)

    rec_books = get_recommendations(user=user, limit=20)
    
    # 返回 JSON
    data = []
    for b in rec_books:
        data.append({
            'id': b.id,
            'title': b.title,
            'image': b.image,
            'tags': b.tags if b.tags else []
        })
    return jsonify({'success': True, 'books': data})

@app.route('/search')
def search_results():
    search_query = request.args.get('q', '') 
    books = []

    if search_query:
        books = Book.query.filter(
            (Book.title.like(f'%{search_query}%')) | 
            (Book.author.like(f'%{search_query}%')) |
            (Book.description.like(f'%{search_query}%'))
        ).all()

    return render_template('search_results.html', books=books, search_query=search_query)

@app.route('/book/<int:book_id>')
def book_detail(book_id):
    books_data = load_books_data()  # 加载所有书籍数据
    book = next((book for book in books_data if book['id'] == book_id), None)  # 查找指定ID的书籍
    if book is None:
        flash('未找到该书籍。', 'danger')
        return redirect(url_for('index'))

    return render_template('book_detail.html', book=book)

@app.route('/api/books', methods=['GET'])
def get_books():
    books = Book.query.all()  # 获取所有书籍
    return jsonify([{
        'id': book.id,
        'title': book.title,
        'author': book.author,
        'image': book.image,
        'description': book.description,
        'tags': book.tags if book.tags else [],  # 直接使用列表
        'epub_path': book.epub_path
    } for book in books])

@app.route('/epub_reader')
def epub_reader():
    book_id = request.args.get('book_id', type=int)  # 确保输入有效
    if not book_id:
        flash('未提供书籍 ID。', 'danger')
        return redirect(url_for('index'))

    # 查询书籍信息
    book = Book.query.get(book_id)
    if not book or not book.epub_path:
        flash('未找到该书籍或缺少电子书路径。', 'danger')
        return redirect(url_for('index'))

    # 传递数据到模板
    return render_template('epub_reader.html', book_id=book.id, book_path=book.epub_path)

@app.route('/api/reading_progress/<int:book_id>', methods=['GET'])
def get_reading_progress(book_id):
    if not session.get('logged_in'):
        return jsonify({'success': False, 'message': '用户未登录'}), 401
    
    user_id = session['user_id']
    rp = ReadingProgress.query.filter_by(user_id=user_id, book_id=book_id).first()
    if not rp:
        return jsonify({'success': True, 'data': {}}), 200
    
    return jsonify({
        'success': True,
        'data': {
            'cfi': rp.cfi,
            'progress_percentage': rp.progress_percentage
        }
    }), 200

@app.route('/api/reading_progress', methods=['POST'])
def update_reading_progress():
    if not session.get('logged_in'):
        return jsonify({'success': False, 'message': '用户未登录'}), 401
    
    data = request.get_json()
    if not data:
        return jsonify({'success': False, 'message': '请求体为空'}), 400

    book_id = data.get('book_id')
    cfi = data.get('cfi')
    progress_percentage = data.get('progress_percentage', 0.0)

    user_id = session['user_id']

    # 查找有没有现成的记录
    rp = ReadingProgress.query.filter_by(user_id=user_id, book_id=book_id).first()
    if not rp:
        # 创建
        rp = ReadingProgress(
            user_id=user_id,
            book_id=book_id,
            cfi=cfi,
            progress_percentage=progress_percentage
        )
        db.session.add(rp)
    else:
        # 更新
        rp.cfi = cfi
        rp.progress_percentage = progress_percentage
    
    db.session.commit()

    return jsonify({'success': True, 'message': '阅读进度已更新'})

#######################
# 评论相关的后端逻辑
#######################
@app.route('/api/reviews/<int:book_id>', methods=['GET'])
def get_book_reviews(book_id):
    """
    获取指定 book_id 的全部评论，包含平均评分。
    返回JSON格式：
    {
      "success": True,
      "reviews": [...],
      "average_rating": 4.5
    }
    """
    book = Book.query.get(book_id)
    if not book:
        return jsonify({'success': False, 'message': '书籍不存在'}), 404

    # 查找所有 review
    reviews = Review.query.filter_by(book_id=book_id).all()

    # 计算平均评分
    ratings = [r.rating for r in reviews if r.rating is not None]
    if len(ratings) > 0:
        avg = sum(ratings) / len(ratings)
    else:
        avg = 0

    # 构造返回列表
    reviews_data = []
    for r in reviews:
        reviews_data.append({
            'id': r.id,
            'username': r.user.username,  # 或者仅显示 'user_id'
            'rating': r.rating,
            'comment': r.comment,
            'created_at': r.created_at.strftime('%Y-%m-%d %H:%M:%S') if r.created_at else ''
        })

    return jsonify({
        'success': True,
        'reviews': reviews_data,
        'average_rating': round(avg, 2)  # 保留两位小数
    }), 200

@app.route('/api/reviews', methods=['POST'])
def add_review():
    """
    处理前端 POST 提交的评论：
    {
      "book_id": 123,
      "rating": 5,
      "comment": "这是评论内容"
    }
    """
    # 如果需要登录才能评论，可在此检查 session
    if not session.get('logged_in'):
        return jsonify({'success': False, 'message': '请先登录'}), 401

    data = request.get_json()
    if not data:
        return jsonify({'success': False, 'message': '请求体为空'}), 400

    book_id = data.get('book_id')
    rating = data.get('rating')
    comment = data.get('comment', '').strip()

    # 校验基本字段
    if not book_id or not rating or not (1 <= rating <= 5):
        return jsonify({'success': False, 'message': '评分范围应在 1~5 且必须传 book_id'}), 400
    if not comment:
        return jsonify({'success': False, 'message': '评论内容不能为空'}), 400

    book = Book.query.get(book_id)
    if not book:
        return jsonify({'success': False, 'message': '书籍不存在'}), 404

    user_id = session['user_id']  # 假设 session 里存了登录用户的 ID
    new_review = Review(
        user_id=user_id,
        book_id=book_id,
        rating=rating,
        comment=comment
    )

    db.session.add(new_review)
    db.session.commit()

    return jsonify({'success': True, 'message': '评论已发布'}), 201


@app.route('/api/user_preference', methods=['POST'])
def update_user_preference():
    """
    请求JSON示例：
    {
        "background_color": "#ffffff",
        "text_color": "#000000",
        "font_size": 18,
        "letter_spacing": 1.5,
        "line_height": 1.8,
        "flip_mode": "both"
    }
    """
    if not session.get('logged_in'):
        return jsonify({'success': False, 'message': '请先登录'}), 401

    data = request.get_json()
    if not data:
        return jsonify({'success': False, 'message': '请求体为空'}), 400

    user_id = session['user_id']
    preference = UserPreference.query.filter_by(user_id=user_id).first()

    # 如果该用户尚未有偏好记录，则创建
    if not preference:
        preference = UserPreference(user_id=user_id)
        db.session.add(preference)

    # 更新字段
    preference.background_color = data.get('background_color', preference.background_color)
    preference.text_color = data.get('text_color', preference.text_color)
    preference.font_size = data.get('font_size', preference.font_size)
    preference.letter_spacing = data.get('letter_spacing', preference.letter_spacing)
    preference.line_height = data.get('line_height', preference.line_height)
    preference.flip_mode = data.get('flip_mode', preference.flip_mode)

    db.session.commit()

    return jsonify({'success': True, 'message': '偏好设置已更新'}), 200

@app.route('/api/user_preference', methods=['GET'])
def get_user_preference():
    if not session.get('logged_in'):
        return jsonify({'success': False, 'message': '请先登录'}), 401

    user_id = session['user_id']
    preference = UserPreference.query.filter_by(user_id=user_id).first()

    if not preference:
        # 如果没有，就返回默认值或空对象
        return jsonify({
            'success': True,
            'data': {
                'background_color': '#ffffff',
                'text_color': '#000000',
                'font_size': 16,
                'letter_spacing': 0,
                'line_height': 1.5,
                'flip_mode': 'both'
            }
        }), 200

    return jsonify({
        'success': True,
        'data': {
            'background_color': preference.background_color,
            'text_color': preference.text_color,
            'font_size': preference.font_size,
            'letter_spacing': preference.letter_spacing,
            'line_height': preference.line_height,
            'flip_mode': preference.flip_mode
        }
    }), 200


@app.route('/bookshelf')
def bookshelf():
    if not session.get('logged_in'):
        flash('请先登录。', 'danger')
        return redirect(url_for('login'))  # 如果用户未登录，重定向到登录页面

    # 获取当前登录用户的书柜，默认为第一个书柜
    user_id = session['user_id']
    bookshelf_id = request.args.get('bookshelf_id', 1, type=int)  # 默认为1
    bookshelf = Bookshelf.query.filter_by(user_id=user_id, id=bookshelf_id).first()

    if bookshelf:
        books = bookshelf.books  # 获取书柜中的书籍列表
        return render_template('bookshelf.html', bookshelf=bookshelf, books=books)
    else:
        flash('没有找到书柜。', 'danger')
        return render_template('bookshelf.html', books=[])

@app.route('/add_to_bookshelf', methods=['POST'])
def add_to_bookshelf():
    data = request.get_json()  # 获取前端传递的 JSON 数据
    bookshelf_id = data.get('bookshelf_id')  # 书柜ID
    book_id = data.get('book_id')  # 书籍ID

    # 查询书柜和书籍
    bookshelf = Bookshelf.query.filter_by(id=bookshelf_id).first()
    book = Book.query.filter_by(id=book_id).first()

    # 如果书柜或书籍不存在，则返回错误
    if not bookshelf or not book:
        return jsonify({'success': False, 'message': '书柜或书籍不存在'}), 400

    # 检查书籍是否已经在书柜中
    if book in bookshelf.books:
        return jsonify({'success': False, 'message': '书籍已经在书柜中'}), 400

    # 使用中间表 bookshelf_book 关联书籍和书柜
    bookshelf.books.append(book)
    db.session.commit()  # 提交事务，将关系保存到数据库

    return jsonify({'success': True, 'message': '书籍已成功添加到书柜'})

@app.route('/remove_from_bookshelf', methods=['DELETE'])
def remove_from_bookshelf():
    data = request.get_json()  # 获取前端传递的 JSON 数据
    bookshelf_id = data.get('bookshelf_id')  # 书柜ID
    book_id = data.get('book_id')  # 书籍ID

    # 查询书柜和书籍
    bookshelf = Bookshelf.query.filter_by(id=bookshelf_id).first()
    book = Book.query.filter_by(id=book_id).first()

    # 如果书柜或书籍不存在，则返回错误
    if not bookshelf or not book:
        return jsonify({'success': False, 'message': '书柜或书籍不存在'}), 400

    # 检查书籍是否在书柜中
    if book not in bookshelf.books:
        return jsonify({'success': False, 'message': '书籍不在书柜中'}), 400

    # 从书柜中移除书籍
    bookshelf.books.remove(book)
    db.session.commit()  # 提交事务，将更改保存到数据库

    return jsonify({'success': True, 'message': '书籍已成功移出书柜'})

@app.route('/get_bookshelf', methods=['GET'])
def get_bookshelf():
    username = session.get('username')
    if not username:
        return jsonify({'message': '用户未登录'}), 400

    user = User.query.filter_by(username=username).first()
    if not user:
        return jsonify({'message': '用户不存在'}), 400

    bookshelf_id = request.args.get('bookshelf_id', 1, type=int)  # 默认为1
    bookshelf = Bookshelf.query.filter_by(user_id=user.id, id=bookshelf_id).first()


    # 返回书柜和书籍数据
    books = [{
        'id': book.id,
        'title': book.title,
        'author': book.author,
        'image': book.image,
        'tags': book.tags,
        'epub_path': book.epub_path
    } for book in bookshelf.books]

    # 确保返回的数据格式正确，并包括书柜名称
    return jsonify({
        'bookshelf_id': bookshelf.id,
        'name': bookshelf.name,  # 添加书柜名称
        'books': books
    })

@app.route('/create_bookshelf', methods=['POST'])
def create_bookshelf():
    username = session.get('username')
    if not username:
        return jsonify({'message': '用户未登录'}), 400

    user = User.query.filter_by(username=username).first()
    if not user:
        return jsonify({'message': '用户不存在'}), 400

    # 获取书柜名称
    data = request.get_json()
    name = data.get('name')

    if not name or name.strip() == '':
        return jsonify({'success': False, 'message': '书柜名称不能为空'}), 400

    # 创建新书柜
    new_bookshelf = Bookshelf(name=name, user=user)
    db.session.add(new_bookshelf)
    db.session.commit()

    # 返回新书柜信息
    return jsonify({
        'success': True,
        'message': '新书柜创建成功',
        'bookshelf_id': new_bookshelf.id
    })

@app.route('/user_bookshelves', methods=['GET'])
def get_user_bookshelves():
    username = session.get('username')
    if not username:
        return jsonify({'message': '用户未登录'}), 400

    user = User.query.filter_by(username=username).first()
    if not user:
        return jsonify({'message': '用户不存在'}), 400

    bookshelves = Bookshelf.query.filter_by(user_id=user.id).all()

    # 返回书柜列表
    bookshelves_data = [{
        'id': bs.id,
        'name': bs.name
    } for bs in bookshelves]

    return jsonify({
        'bookshelves': bookshelves_data
    })

# 配置上传目录和允许的文件类型
UPLOAD_FOLDER = os.path.join(app.root_path, 'static', 'uploads')
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

# 确保上传目录存在
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

# 检查文件是否是允许的类型
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/profile')
def profile():
    user_status = {
        "name": "未登录",
        "actions": ["立即登录"],
    }

    # 检查登录状态
    logged_in = session.get('logged_in', False)
    if logged_in:
        user_status["name"] = session.get('username', "用户")
        user_status["actions"] = ["退出登录"]
        user_status["logout_link"] = url_for('logout')

    avatar_path = url_for('static', filename=get_avatar_path(logged_in))

    membership_info = {
        "membership": "书库会员",
        "status": "您还不是书库会员",
        "membership_actions": ["立即开通"]
    }

    benefits = [
        {"icon_path": "no_ads.svg", "label": "多端免广告"},
        {"icon_path": "avatar_frame.svg", "label": "专属头像设置"},
        {"icon_path": "app_icon.svg", "label": "专属应用"},
        {"icon_path": "ai_upgrade.svg", "label": "AI功能提升"}
    ]

    sections = [
        {"icon_path": "favorites.svg", "label": "收藏条目"},
        {"icon_path": "recently_viewed.svg", "label": "最近浏览"},
        {"icon_path": "cute_power.svg", "label": "书力值"},
        {"icon_path": "game_center.svg", "label": "游戏中心"}
    ]

    other_links = [
        {"label": "帮助中心", "link": "#", "icon_path": "help_center.svg"},
        {"label": "关于", "link": "#", "icon_path": "about.svg"}
    ]

    user = {"avatar_path": avatar_path}
    return render_template('profile.html', user_status=user_status, membership_info=membership_info,
                           benefits=benefits, sections=sections, other_links=other_links, user=user)

@app.context_processor
def inject_time_function():
    return {'time': lambda: int(time.time())}

@app.route('/upload_avatar', methods=['POST'])
def upload_avatar():
    if 'avatar' not in request.files:
        return "No file part", 400

    file = request.files['avatar']
    if file.filename == '':
        return "No selected file", 400

    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)

        # 创建 uploads 目录（如果不存在）
        os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

        if os.path.exists(file_path):
            # 强制删除旧文件以更新时间戳
            os.remove(file_path)

        # 保存新文件
        file.save(file_path)

        # 设置 session 或其他持久化逻辑
        session['avatar_path'] = f'uploads/{filename}'
        flash('头像上传成功！', 'success')
        return redirect(url_for('profile'))
    else:
        return "Invalid file type", 400

@app.route('/membership')
def membership():
    return render_template('membership.html')

@app.route('/game_center')
def game_center():
    games = [
        {"name": "1、扫雷网页版游戏", "url": "https://www.minesweeper.cn/"},
        {"name": "2、捏人动漫", "url": "https://picrew.me/ja/"},
        {"name": "3、中午吃什么", "url": "http://chishenme.xyz/"}
    ]
    return render_template('game_center.html', games=games)

@app.route('/book_power')
def book_power():
    # 获取点击书力值的次数，默认是0
    book_power_count = session.get('book_power_count', 0)

    # 渲染 book_power.html 模板，传递当前的书力值
    return render_template('book_power.html', book_power_count=book_power_count)

@app.route('/increase_book_power')
def increase_book_power():
    # 增加书力值点击次数
    book_power_count = session.get('book_power_count', 0) + 1
    session['book_power_count'] = book_power_count

    # 重定向到书力值页面
    return redirect(url_for('book_power'))

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        confirm_password = request.form.get('confirm_password')

        if len(username) < 3 or len(username) > 20:
            flash('用户名长度必须在3到20之间', 'danger')
            return redirect(url_for('register'))
        if len(password) < 6:
            flash('密码长度必须至少为6', 'danger')
            return redirect(url_for('register'))
        if password != confirm_password:
            flash('两次输入的密码不匹配', 'danger')
            return redirect(url_for('register'))

        existing_user = User.query.filter((User.username == username)).first()
        if existing_user:
            flash('用户名已被注册', 'danger')
            return redirect(url_for('register'))

        hashed_password = generate_password_hash(password) 
        new_user = User(username=username, password=hashed_password)
        db.session.add(new_user)
        db.session.commit()  

        # 创建默认书柜
        default_bookshelf = Bookshelf(name="默认书柜", user_id=new_user.id)
        db.session.add(default_bookshelf)
        db.session.commit()

        # 自动创建用户阅读偏好
        default_preference = UserPreference(
            user_id=new_user.id,
            background_color='#ffffff',
            text_color='#000000',
            font_size=16,
            letter_spacing=0,
            line_height=1.5,
            flip_mode='both'
        )
        db.session.add(default_preference)
        db.session.commit()

        flash('注册成功！请登录。', 'success')
        return redirect(url_for('login'))  

    return render_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # 获取表单数据
        username = request.form.get('username')
        password = request.form.get('password')

        # 查询数据库中的用户
        user = User.query.filter_by(username=username).first()

        if user and check_password_hash(user.password, password):
            # 登录成功，设置 session
            session['logged_in'] = True
            session['username'] = user.username
            session['user_id'] = user.id  # 将用户 ID 存储到 session 中

            # 获取用户的默认书柜
            default_bookshelf = Bookshelf.query.filter_by(user_id=user.id).first()
            session['bookshelf_id'] = default_bookshelf.id if default_bookshelf else None  
            flash('登录成功！', 'success')
            return redirect(url_for('index'))  # 登录成功后跳转到主页
        else:
            flash('用户名或密码错误', 'danger')
            return redirect(url_for('login'))  # 登录失败时重定向到登录页面

    return render_template('login.html')  # 如果是 GET 请求，渲染登录页面

@app.route('/logout')
def logout():
    session.pop('logged_in', None)
    session.pop('username', None)
    session.pop('user_id', None)
    session.pop('bookshelf_id', None)
    flash('您已成功退出登录。', 'info')
    return redirect(url_for('index'))  # 退出后跳转到主页

@app.route('/welcome')
def welcome():
    if session.get('logged_in'):
        return redirect(url_for('index'))
    else:
        flash('请先登录。', 'danger')
        return redirect(url_for('login'))

if __name__ == '__main__':
    with app.app_context():
        db.create_all()  # 创建所有模型对应的表
        print("数据库表已成功创建！")
    app.run(debug=True, host='0.0.0.0', port=5000)
